[Day17](謎:今天要用哪一張圖呢?)Baby5:明白!是需要我吧!
接著再介紹一個 Ruby 的重要概念(每個都很重要...結果就都不重要了)
anyway 要登場的就是 Block (鏘鏘!)
也可以稱作「(程式碼)區塊」,只是很少這麼叫它就是了。
雖然和數位金融領域近幾年很熱門的:區塊鏈(Blockchain) 兩者名字很像,但 Block 和 Blockchain 兩者完全不一樣,有興趣了解區塊鏈的朋友可以右轉到 TaiwanBar:
抱歉跑題了...
接著就開始介紹 Block 吧!希望能把它解釋清楚~
首先,Block 是 Ruby 裡少數不是物件的存在,它也是一段不會被主動執行的程式碼,並且在實務上被大量地使用在 Rails 裡。
Block 有兩種表示方式:
{
... # Block 要做的事
}
do...end
寫法do
... # Block 要做的事
end
看起來是不是有點像閹割版的方法?但其實不太一樣喔!
我們直接來看例子:
list = [1, 2, 3]
p list.map{ |i| i + 2 }
# 印出
[3, 4, 5]
p list.map do |i| i + 2 end
# 印出
#<Enumerator: [1, 2, 3]:map>
What?! 為什麼會這樣?其實是因為 Ruby 語言經常會省略小括號 ()
,實際上這兩行長成這樣:
list = [1, 2, 3]
p(list.map{ |i| i + 2 })
# 印出
[3, 4, 5]
p(list.map) do |i| i + 2 end
# 印出
#<Enumerator: [1, 2, 3]:map>
由於 do...end
的優先級較低,所以先跟 p 結合了,後面的 Block 就被忽略了...(存在感真低啊)
|i|
是什麼?啊那個其實只是一個變數,通常會在要傳一個東西進到 Block 的時候使用,或是方法在轉讓控制權(yield)時帶出了參數,就可以把參數放進 Block 讓它去執行。
另外,在上面的例子裡不能省略,因為 |i|
在此代表著 list
陣列中的每一個值。
當然 |i|
只是個變數,要把它改成 a
、b
或 value
也行,不過裡面外面都要用同樣的名稱才行。
因為 Block 無法在程式環境忍受孤獨(誤),如果只有 Block 存在的話會造成語法錯誤:
{
puts "我是大括號型的 Block"
}
# 印出
#syntax error, unexpected '}', expecting end-of-input
do
puts "我是 do...end 型的 Block"
end
# 印出
#syntax error, unexpected end, expecting end-of-input
以上兩種語法都沒辦法執行!
在程式裡,Block 必須依附在某個方法後面,只能寄居人下非常可憐,而 Block 會不會動(能否執行),要看所依附的方法同不同意讓 Block 執行,完全就是看人臉色的可撥仔!
我們來看看它被邊緣的模樣:
def jump(name)
puts "#{name}跳起來!"
end
jump("喬巴") {
puts "我是大括號型的 Block"
}
# do ... end 寫法
jump("喬巴") do
puts "我是 do...end 型的 Block"
end
參數是name
,而不是 Block
雖然執行上面這段程式碼不會有任何錯誤,但 Block 裡寫好的程式也不會執行...
如果要讓 Block 動起來,必須在方法裡加上一個 yield
才行:
def say_hello
puts "安安, "
yield
puts "幾歲?"
end
say_hello {
puts "你好!"
}
puts "住哪?"
# 印出
安安,
你好!
幾歲?
住哪?
不過,要理解 Block 的運作原理,還必須知道 scope
和 yield
的概念才行。
今天就先到這邊啦!明天我會繼續說明 Block 的概念~
參考來源:
為你自己學 Ruby on Rails - 方法與程式碼區塊
五倍紅寶石 - Proc是什麼可以吃嗎